package com.example.demo2.define;


import com.example.demo2.action.*;
import com.example.demo2.guard.PlayGuard;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;

@Configuration
@EnableStateMachine
public class CDStateMachineConfig extends EnumStateMachineConfigurerAdapter<CDStates, CDEvents> {
    @Override
    public void configure(StateMachineStateConfigurer<CDStates, CDEvents> states)
            throws Exception {
        //初始状态 IDLE
        states.withStates()
                .initial(CDStates.IDLE)
                .state(CDStates.IDLE)

                //IDLE的子状态
                .and()
                .withStates()
                    .parent(CDStates.IDLE)
                    .initial(CDStates.CLOSED)
                    .state(CDStates.CLOSED, closedEntryAction(), null)
                    .state(CDStates.OPEN)

                //BUSY 状态及其子状态
                .and()
                .withStates()
                    .state(CDStates.BUSY)
                    .and()
                    .withStates()
                    .parent(CDStates.BUSY)
                    .initial(CDStates.PLAYING)
                    .state(CDStates.PLAYING)
                    .state(CDStates.PAUSED);
    }

    /**
     * 配置状态机的事件转换
     * @param transitions
     * @throws Exception
     */
    @Override
    public void configure(StateMachineTransitionConfigurer<CDStates, CDEvents> transitions)
            throws Exception {
        //IDLE状态下的子状态的转换关系
        //IDLE 的子状态: CLOSED 和 OPEN
        transitions
                //OPEN <-> CLOSED 转换的事件
                //CLOSE -> OPEN 通过事件 [EJECT] 弹出键
        .withExternal()
                    .source(CDStates.CLOSED).target(CDStates.OPEN).event(CDEvents.EJECT)
                    .and()
                //OPEN -> CLOSED 通过事件 [EJECT] 弹出键
        .withExternal()
                    .source(CDStates.OPEN).target(CDStates.CLOSED).event(CDEvents.EJECT)
                    .and()
        .withExternal()
                    .source(CDStates.OPEN).target(CDStates.CLOSED).event(CDEvents.PLAY)
                    .and()
        //BUSY状态下的子状态的转换关系
        //BUSY的子状态：PLAYING 和 PAUSED
        .withExternal()
                    .source(CDStates.PLAYING).target(CDStates.PAUSED).event(CDEvents.PAUSE)
                    .and()
                //定时播放动作 注意这里是withInternal 定义内部转换，即在同一个状态内部发生的转换
                .withInternal()
                    .source(CDStates.PLAYING)
                    .action(playingAction())
                    .timer(1000)  //定时触发 即1s自动触发一次（使状态机能够周期性的执行某个动作，而不需要外部事件触发）
                    .and()
                // 快退快进操作 都是在 PLAYING 状态下发生的
                .withInternal()
                    .source(CDStates.PLAYING).event(CDEvents.BACK)
                    .action(trackAction())
                    .and()
                .withInternal()
                    .source(CDStates.PLAYING).event(CDEvents.FORWARD)
                    .action(trackAction())
                    .and()

        .withExternal()
                    .source(CDStates.PAUSED).target(CDStates.PLAYING).event(CDEvents.PAUSE)
                    .and()



                //========  BUSY <-> IDLE 2个父类的状态的状态的转换
                //  BUSY -> IDLE
        .withExternal()
                    .source(CDStates.BUSY).target(CDStates.IDLE).event(CDEvents.STOP)
                    .and()

                // IDLE -> BUSY (开始播放)
        .withExternal()
                    .source(CDStates.IDLE).target(CDStates.BUSY).event(CDEvents.PLAY)
                    .action(playAction())
                    .guard(playGuard()) //满足guard的条件下，执行对应的action
                    .and()

                //IDLE状态下的子sub state open
                .withInternal()
                    .source(CDStates.OPEN).event(CDEvents.LOAD)
                    .action(loadAction())
        ;
    }

    @Override
    public void configure(StateMachineConfigurationConfigurer<CDStates, CDEvents> config) throws Exception {
        config.withConfiguration()
                .autoStartup(true);  // 自动启动
    }

    // ======== Action Beans ========
    //将所有的 @Bean 方法统一放在类的末尾，并加上适当的注释。
    @Bean
    public ClosedEntryAction closedEntryAction() {
        return new ClosedEntryAction();
    }

    @Bean
    public LoadAction loadAction() {
        return new LoadAction();
    }

    @Bean
    public TrackAction trackAction() {
        return new TrackAction();
    }

    @Bean
    public PlayAction playAction() {
        return new PlayAction();
    }

    @Bean
    public PlayingAction playingAction() {
        return new PlayingAction();
    }

    // ======== Guard Beans ========
    @Bean
    public PlayGuard playGuard() {
        return new PlayGuard();
    }

}
